from odoo import fields, models, api
from odoo.exceptions import UserError, ValidationError
from ...functions.common import is_continuous
from ..setting.rp_weight_gradient_template import WEIGHT_TYPE
from .rp_courier_mail_route import EXPRESS_CATEGORY


class RPShipperSaleTemplateValueAddedLine(models.Model):
    _name = 'rp.shipper.sale.template.value.added.line'
    _description = '托运商销售价增值明细'
    _sql_constraints = [('unique_code', 'UNIQUE(code)', '编码不允许重复')]
    _rec_name = 'code'
    _order = 'code ASC'

    rp_shipper_sale_template_id = fields.Many2one(string='关联主表', comodel_name='rp.shipper.sale.template', required=True, ondelete='cascade')
    code = fields.Char(string='编码', default='New', readonly=True, copy=False, index=True)

    shipper_id = fields.Many2one(string='托运商', comodel_name='rp.shipper', related='rp_shipper_sale_template_id.shipper_id', store=True)
    shipper_value_added_id = fields.Many2one(string='增值服务', comodel_name='rp.value.added.service')
    shipper_value_added_category = fields.Selection(string='增值服务大类', related='shipper_value_added_id.category')

    sale_price = fields.Monetary(string='定价', default=0)
    currency_id = fields.Many2one(string='货币单位', comodel_name='res.currency', default=lambda self: self.env.company.currency_id)
    active_flag = fields.Boolean(string='有效', related='rp_shipper_sale_template_id.active_flag', store=True)

    @api.model_create_multi
    def create(self, vals_list):
        """
        托运商增值定价的编码规则：
        1、根据增值服务寻找邮路的定价明细，如果有，则用同一个编码
        2、如果找不到则采用编码表编码方式编码
        """
        value_list = []
        shipper_id = None
        courier_id = None
        for vals in vals_list:
            value_added = vals.get('shipper_value_added_id')
            rp_shipper_sale_template_id = vals.get('rp_shipper_sale_template_id')
            shipper_id = self.env['rp.shipper.sale.template'].search([('id', '=', rp_shipper_sale_template_id)]).shipper_id
            courier_id = shipper_id.courier_id
            courier_cost_template_value_added = self.env['rp.courier.cost.template.value.added.line'].search([('courier_value_added_id', '=', value_added),
                                                                                                              ('courier_id', '=', courier_id.id),
                                                                                                              ('active_flag', '=', True)])
            if courier_cost_template_value_added:
                vals.update({'code': "'" + str(courier_cost_template_value_added.code)})
            else:
                # 修改逻辑
                # rp_shipper_sale_template_id = vals.get('rp_shipper_sale_template_id')
                # prefix = self.env['rp.shipper.sale.template'].search([('id', '=', rp_shipper_sale_template_id)]).shipper_id.code
                # code = self.env['rp.sequence.code'].explore_sequence(model=self._name, prefix=prefix, key='VL', padding=4)
                # vals.update({'code': code})
                value = self.env['rp.value.added.service'].browse(value_added).name
                value_list.append(value)
        if value_list:
            value_name = ','.join(value_list)
            raise UserError("未在%s托运商所对应的 [%s承运商] 的成本模板中配置 [%s] 相关的增值服务成本明细" % (shipper_id.name,
                                                                                                              courier_id.name,
                                                                                                              value_name))
        result = super(RPShipperSaleTemplateValueAddedLine, self).create(vals_list)
        return result

    def name_get(self):
        res = []
        for s in self:
            name = s._get_name()
            res.append((s.id, name))
        return res

    def _get_name(self):
        """ 重写display_name """
        name = self.code
        if self._context.get('show_display'):
            display_name = self.shipper_value_added_id.name if self.shipper_value_added_id else ''
            code = self.code if self.code else ''

            name = code + ' - ' + display_name

        return name


class RPShipperSaleTemplateLine(models.Model):
    _name = 'rp.shipper.sale.template.mail.route.line'
    _description = '托运商销售价邮路明细'
    _rec_name = 'code'
    _sql_constraints = [('unique_code', 'UNIQUE(code)', '编码不允许重复')]
    _order = 'code ASC'

    def _default_get_kg(self):
        kg = self.env['uom.uom'].search([('name', '=', 'kg')])
        return kg.id if kg else False

    rp_shipper_sale_template_id = fields.Many2one(string='关联主表', comodel_name='rp.shipper.sale.template', ondelete='cascade')
    code = fields.Char(string='编码', default='New', readonly=True, copy=False, index=True)

    shipper_id = fields.Many2one(string='托运商', comodel_name='rp.shipper', related='rp_shipper_sale_template_id.shipper_id', store=True)
    shipper_mail_route_id = fields.Many2one(string='托运商邮路', comodel_name='rp.shipper.mail.route')
    package_type_ids = fields.Many2many(string='包裹类型', comodel_name='rp.package.type', related='shipper_mail_route_id.package_type_ids',
                                        relation='rp_shipper_stmr_line_and_package_type_rel', column1='line_id', column2='package_type_id')

    aging_available_ids = fields.Many2many(string='可用时效', comodel_name='rp.aging', related='shipper_mail_route_id.aging_ids')
    aging_id = fields.Many2one(string='时效', comodel_name='rp.aging')

    ship_from_country_group_available_ids = fields.Many2many(string='可用启运地', comodel_name='res.country.group', related='shipper_mail_route_id.ship_from_country_group_ids')
    ship_to_country_group_available_ids = fields.Many2many(string='可用目的地', comodel_name='res.country.group', related='shipper_mail_route_id.ship_to_country_group_ids')
    same_city_flag = fields.Boolean(string='同城', related='shipper_mail_route_id.same_city_flag', readonly=True, store=True)
    same_province_flag = fields.Boolean(string='同省', related='shipper_mail_route_id.same_province_flag', readonly=True, store=True)
    express_category = fields.Selection(string='发件类型', selection=EXPRESS_CATEGORY, related='shipper_mail_route_id.express_category', readonly=True, store=True)
    ship_from_country_group_ids = fields.Many2many(string='启运地', comodel_name='res.country.group', relation='rp_sale_line_ship_from_and_country_groups_rel', column1='sale_line_id', column2='country_group_id')
    ship_to_country_group_ids = fields.Many2many(string='目的地', comodel_name='res.country.group', relation='rp_sale_line_ship_to_and_country_groups_rel', column1='sale_line_id', column2='country_group_id')

    weight_gradient_type = fields.Selection(string='重量梯度类型', selection=WEIGHT_TYPE, default=WEIGHT_TYPE[0][0], required=True)
    weight_gradient_template_id = fields.Many2one(string='重量梯度模板', comodel_name='rp.weight.gradient.template', domain="[('type','=',weight_gradient_type)]", help='只简便配置，不参与逻辑')
    price_adjust_id = fields.Many2one(string='统一改价', comodel_name='rp.price.adjust.rule', domain=[('rule', '=', 'rate_up')], help='只简便配置，不参与逻辑')

    shipper_sale_template_line_ids = fields.One2many(string='关联重量明细', comodel_name='rp.shipper.sale.template.weight.line', inverse_name='shipper_sale_template_weight_line_id')
    inf = fields.Float(string='下确界', compute='_depends_compute_bounds', store=True, digits=(5, 2), default=0)
    sup = fields.Float(string='上确界', compute='_depends_compute_bounds', store=True, digits=(5, 2), default=0)

    active_flag = fields.Boolean(string='有效', related='rp_shipper_sale_template_id.active_flag', store=True)

    @api.onchange('shipper_mail_route_id')
    def _onchange_courier_mail_route_id(self):
        if self.shipper_mail_route_id:
            self.update({'aging_id': False,
                         'ship_from_country_group_ids': False,
                         'ship_to_country_group_ids': False})

    @api.onchange('weight_gradient_type')
    def _onchange_weight_gradient_type(self):
        if self.weight_gradient_type:
            self.update({'weight_gradient_template_id': False})

    @api.onchange('ship_from_country_group_ids', 'ship_to_country_group_ids')
    def _onchange_from_to_groups(self):
        if self.same_province_flag or self.same_city_flag:
            # 只有启运地无目的地
            if len(self.ship_from_country_group_ids.ids) > 0 and len(self.ship_to_country_group_ids.ids) == 0:
                self.update({'ship_to_country_group_ids': [(6, 0, self.ship_from_country_group_ids.ids)]})
            # 只有目的地无启用地
            if len(self.ship_to_country_group_ids.ids) > 0 and len(self.ship_from_country_group_ids.ids) == 0:
                self.update({'ship_from_country_group_ids': [(6, 0, self.ship_from_country_group_ids.ids)]})
            # 启运地和目的地都存在以启运地为准
            if len(self.ship_from_country_group_ids.ids) > 0 and len(self.ship_to_country_group_ids.ids) > 0:
                self.update({'ship_to_country_group_ids': [(6, 0, self.ship_from_country_group_ids.ids)]})

    @api.depends('shipper_sale_template_line_ids.min_weight', 'shipper_sale_template_line_ids.max_weight')
    def _depends_compute_bounds(self):
        """ 计算上确界和下确界 """
        for s in self:
            if s.shipper_sale_template_line_ids:
                intervals = []
                for wgt in s.shipper_sale_template_line_ids:
                    intervals.append((wgt.min_weight, wgt.max_weight))
                flag, inf, sup = is_continuous(intervals)
                if not flag:
                    raise UserError('所配置的重量梯度非连续')
                s.write({'inf': inf, 'sup': sup})

    @api.model_create_multi
    def create(self, vals_list):
        """
        托运商邮路定价的编码规则：
        1、根据邮路、时效、启运地、目的地寻找邮路的定价明细，如果有，则用同一个编码
        2、如果找不到则采用编码表编码方式编码
        """
        for vals in vals_list:
            shipper_mail_route_id = vals.get('shipper_mail_route_id')
            aging_id = vals.get('aging_id')
            ship_from_country_group_ids = vals.get('ship_from_country_group_ids')[0][2]
            ship_to_country_group_ids = vals.get('ship_to_country_group_ids')[0][2]
            courier_mail_route = self.env['rp.shipper.mail.route'].search([('id', '=', shipper_mail_route_id)]).courier_mail_route_id
            courier_cost_cost_template_mail_route = self.env['rp.courier.cost.template.mail.route.line'].search([('courier_mail_route_id', '=', courier_mail_route.id),
                                                                                                                 ('aging_id', '=', aging_id),
                                                                                                                 ('ship_from_country_group_ids', '=', ship_from_country_group_ids),
                                                                                                                 ('ship_to_country_group_ids', '=', ship_to_country_group_ids)])
            if courier_cost_cost_template_mail_route:
                vals.update({'code': "'" + str(courier_cost_cost_template_mail_route.code)})
            else:
                rp_shipper_sale_template_id = vals.get('rp_shipper_sale_template_id')
                prefix = self.env['rp.shipper.sale.template'].search([('id', '=', rp_shipper_sale_template_id)]).shipper_id.code
                code = self.env['rp.sequence.code'].explore_sequence(model=self._name, prefix=prefix, key='CS', padding=5)
                vals.update({'code': code})
        result = super(RPShipperSaleTemplateLine, self).create(vals_list)
        return result

    @api.onchange('weight_gradient_template_id')
    def _fulfill_weight_line(self):
        if self.weight_gradient_template_id:
            create_list = []
            for wgt in self.weight_gradient_template_id.weight_gradient_template_ids:
                values = {'min_weight': wgt.min_weight,
                          'max_weight': wgt.max_weight,
                          'carry_value': wgt.carry_value,
                          'uom_id': wgt.uom_id.id}
                create_list.append((0, 0, values))
            self.update({'shipper_sale_template_line_ids': [(5, 0, 0)]})
            self.update({'shipper_sale_template_line_ids': create_list})

    @api.onchange('price_adjust_id')
    def _onchange_price_adjust(self):
        if self.price_adjust_id and self.shipper_sale_template_line_ids:
            for stl in self.shipper_sale_template_line_ids:
                stl.update({'start_price': stl.start_price * (1 + self.price_adjust_id.rated_float),
                            'carry_price': stl.carry_price * (1 + self.price_adjust_id.rated_float)})

    def name_get(self):
        res = []
        for s in self:
            name = s._get_name()
            res.append((s.id, name))
        return res

    def _get_name(self):
        """ 重写display_name """
        name = self.code
        if self._context.get('show_display'):
            display_name = self.shipper_mail_route_id.name if self.shipper_mail_route_id else ''
            code = self.code if self.code else ''

            name = code + ' - ' + display_name

        return name


class RPShipperSaleTemplateWeightLine(models.Model):
    _name = 'rp.shipper.sale.template.weight.line'
    _description = '托运商销售价重量明细'
    _order = 'min_weight ASC'

    def _default_get_kg(self):
        kg = self.env['uom.uom'].search([('name', '=', 'kg')])
        return kg.id if kg else False

    shipper_sale_template_weight_line_id = fields.Many2one(string='关联主表', comodel_name='rp.shipper.sale.template.mail.route.line', ondelete='cascade')

    min_weight = fields.Float(string='最小重量', digits=(5, 2), default=0, required=True)
    max_weight = fields.Float(string='最大重量', digits=(5, 2), default=0, required=True)
    uom_id = fields.Many2one(string='重量单位', comodel_name='uom.uom', default=_default_get_kg)

    carry_value = fields.Float(string='进位值', digits=(3, 2), default=0, required=True)

    start_price = fields.Float(string='首重价', digits=(5, 3), default=0, required=True)
    carry_price = fields.Float(string='进位价', digits=(5, 3), default=0)
    currency_id = fields.Many2one(string='货币单位', comodel_name='res.currency', default=lambda self: self.env.company.currency_id)
